<template>
  <div
    v-if="selectedElements.length === 1"
    class="custom-properties-panel"
  >
    <el-form
      ref="panelDataForm"
      :model="formData"
      label-width="85px"
      :inline="false"
      label-position="right"
    >
      <el-form-item :label="isLine ? '线路名称' : '节点名称'" prop="name">
        <el-input v-model="formData.name"></el-input>
      </el-form-item>
      <el-form-item label="节点排序" prop="ordinal" v-if="isNode">
        <ac-number v-model="formData.ordinal" :min="1"></ac-number>
      </el-form-item>
      <el-form-item :label="isLine ? '线路颜色' : '节点颜色'" prop="color">
        <el-color-picker v-model="formData.color" :predefine="predefineColors" />
      </el-form-item>
      <el-form-item label="可否取回" prop="canBack" v-if="isTask">
        <ac-dict-switch v-model="formData.canBack" dictCode="dictYesNo" />
      </el-form-item>
      <!--
      <el-form-item label="可被退回" prop="canBeBack" v-if="isTask">
        <ac-dict-switch v-model="formData.canBeBack" dictCode="dictYesNo" />
      </el-form-item>
      -->
      <el-form-item label="可否办结" prop="canStop" v-if="isTask">
        <ac-dict-switch v-model="formData.canStop" dictCode="dictYesNo" />
      </el-form-item>
      <el-form-item label="电子签名" prop="signatureType" v-if="isTask">
        <ac-dict-select v-model="formData.signatureType" dictCode="dictFlowSignature" />
      </el-form-item>
      <el-form-item label="节点模型" prop="modelId" v-if="isTask">
        <ac-tree
          v-model="formData.modelId"
          data-url="/system/dataModel/queryTree"
          typeSelect="model"
        />
      </el-form-item>
      <el-form-item label="标题字段" prop="titleFieldName" v-if="isTask">
        <ac-remote-select
          v-if="formData.modelId"
          v-model="formData.titleFieldName"
          data-url="/system/dataField/queryList"
          :query="{modelId: formData.modelId}"
          idProp="fieldName"
          nameProp="showName"
          :loadAll="true"
        />
        <el-select v-else placeholder="--请选择--"></el-select>
      </el-form-item>
      <el-form-item label="编辑页面" prop="editPageId" v-if="isTask">
        <ac-tree
          v-model="formData.editPageId"
          data-url="/system/page/queryTree"
          type-select="page"
          @change="changeEditPage"
        />
      </el-form-item>
      <el-form-item
        v-if="formData.editPageId && editPageParamList.length > 0"
        label="出参配置"
        prop="pageId"
      >
        <div class="param-item">
          <div class="param-field">
            <el-input v-model="dataName" disabled />
          </div>
          <div class="param-split"><ac-icon iconId="018eecae20bd010c2adf" /></div>
          <div class="param-page">
            <el-select
              v-model="formData.editPageDataParamId"
              class="cc-select"
              :filterable="true"
              placeholder="--请选择--"
              clearable
            >
              <el-option
                v-for="item in editPageParamList"
                :key="item.id"
                :value="item.id"
                :label="item.name"
              />
            </el-select>
          </div>
        </div>
      </el-form-item>
      <el-form-item label="详情页面" prop="viewPageId" v-if="isTask">
        <ac-tree
          v-model="formData.viewPageId"
          data-url="/system/page/queryTree"
          type-select="page"
          @change="changeViewPage"
        />
      </el-form-item>
      <el-form-item
        v-if="formData.viewPageId && viewPageParamList.length > 0"
        label="出参配置"
        prop="pageId"
      >
        <div style="display: flex;flex-direction: column">
          <div class="param-item">
            <div class="param-field">
              <el-input v-model="dataName" disabled />
            </div>
            <div class="param-split"><ac-icon iconId="018eecae20bd010c2adf" /></div>
            <div class="param-page">
              <el-select
                v-model="formData.viewPageDataParamId"
                class="cc-select"
                :filterable="true"
                placeholder="--请选择--"
                clearable
              >
                <el-option
                  v-for="item in viewPageParamList"
                  :key="item.id"
                  :value="item.id"
                  :label="item.name"
                />
              </el-select>
            </div>
          </div>
        </div>
      </el-form-item>
      <el-form-item label="发起子流程" prop="canSubFlow" v-if="isTask">
        <ac-dict-switch
          v-model="formData.canSubFlow"
          dict-code="dictYesNo"
        />
      </el-form-item>
      <el-form-item label="子流程名称" prop="subFlowId" v-if="isTask && formData.canSubFlow === '1'">
        <ac-remote-select
          v-model="formData.subFlowId"
          dataUrl="/system/flow/queryPage"
          load-all
        />
      </el-form-item>
      <el-form-item label="参数配置" prop="subFlowParam" v-if="isTask && formData.canSubFlow === '1'">
        <ac-icon
          iconId="018ece4f712124866f78"
          size="20"
          style="cursor: pointer"
          @click="openFlowParam"
        />
      </el-form-item>
      <el-form-item label="执行脚本" prop="scriptId" v-if="isScriptTask">
        <ac-tree
          v-model="formData.scriptId"
          data-url="/system/scriptGroovy/queryTree"
          type-select="script"
        />
      </el-form-item>
      <el-form-item label="消息类型" prop="ordinal" v-if="isTask || isSendTask">
        <ac-checkbox v-model="formData.messageType" :options="[{key: '1', value: '站内消息'}]"></ac-checkbox>
      </el-form-item>
      <el-form-item label="消息模板" prop="ordinal" v-if="isTask || isSendTask">
        <el-input v-model="formData.messageTpl" type="textarea" :rows="3"></el-input>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="formData.remark" type="textarea" :rows="3"></el-input>
      </el-form-item>
    </el-form>

    <el-dialog
      v-model="batchDialogVisible"
      title="流程入参配置"
      width="900px"
      :close-on-click-modal="false"
      class="batch-dialog"
      destroy-on-close
      draggable
      append-to-body
    >
      <div style="min-height: 350px">
        <div style="margin-bottom: 5px;">
          <span>新增&nbsp;
          <el-input
            v-model.number="newRow"
            size="default"
            style="width:50px"
          ></el-input>&nbsp;行&nbsp;</span>
          <el-button size="default" type="success" @click="addNew">添加 {{newRow}} 行</el-button>
        </div>
        <el-form
          :model="batchFormData"
          label-width="0px"
          ref="batchDataForm"
          label-position="right"
        >
          <el-table
            class="edit-table"
            style="width:100%;"
            :data="batchFormData.list"
            width="100%"
            :border="true"
          >
            <template #empty>
              <div class="el-table__empty-block">
                <img src="@/assets/images/no-data.png" style="width: 100px" alt />
                <span style="min-width: 100px">暂无数据</span>
              </div>
            </template>
            <el-table-column label="出参节点" header-align="center" min-width="100">
              <template v-slot="{ row, $index }">
                <el-form-item :prop="'list.' + $index +'.nodeId'" :rules="batchRules.sourceNodeId">
                  <el-select v-model="row.nodeId" @change="changeNode(row)">
                    <el-option
                      v-for="node in sourceNodeList.filter(item => item.modelId)"
                      :key="node.id"
                      :value="node.id"
                      :label="node.name"
                    >{{node.name}}</el-option>
                  </el-select>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="出参字段" header-align="center" min-width="100">
              <template v-slot="{ row, $index }">
                <el-form-item :prop="'list.' + $index +'.sourceFieldName'" :rules="batchRules.sourceFieldName">
                  <el-select v-model="row.sourceFieldName">
                    <el-option
                      v-for="field in row.sourceFieldList || []"
                      :key="field.id"
                      :value="field.fieldName"
                    >{{field.showName}}</el-option>
                  </el-select>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="入参字段" header-align="center" min-width="100">
              <template v-slot="{ row, $index }">
                <el-form-item :prop="'list.' + $index +'.targetFieldName'" :rules="batchRules.targetFieldName">
                  <el-select v-model="row.targetFieldName">
                    <el-option
                      v-for="field in targetFieldList || []"
                      :key="field.id"
                      :value="field.fieldName"
                    >{{field.showName}}</el-option>
                  </el-select>
                </el-form-item>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="80" header-align="center" align="center">
              <template v-slot="{ row }">
                <el-button
                  type="danger"
                  @click="handleDeleteRow(row)"
                  link
                >删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-form>
      </div>
      <template #footer>
        <el-button
          size="default"
          type="info"
          @click="batchDialogVisible=false"
        >取消</el-button>
        <el-button
          type="primary"
          size="default"
          @click="submitBatchForm"
        >确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, toRaw, watch, computed, onMounted } from 'vue';
import { getLightColor } from "@/utils/theme";
import api from "@/http/api";
import { ElMessage } from 'element-plus';
import tool from "@/utils/tool";

const props = defineProps({
  option: {
    type: Object,
    default: () => ({})
  },
  modeler: {
    type: Object
  }
});

const formData = ref({});
const selectedElements = ref([]);
const currElement = ref(null);
const modeler = ref(null);
const predefineColors = ref([
  '#409EFF',
  '#67C23A',
  '#E6A23C',
  '#F56C6C',
  '#909399',
  '#ff4500',
  '#ff8c00',
  '#ffd700',
  '#90ee90',
  '#00ced1',
  '#1e90ff',
  '#c71585',
  '#FF7800',
]);
const dataName = ref('数据id');
const editPageParamList = ref([]);
const viewPageParamList = ref([]);

const newRowFlag = ref(1);
const newRow = ref(1);
const batchDialogVisible = ref(false);
const batchRules = ref({
  sourceNodeId: [{required: true, message: '请选择出参节点', trigger: 'blur'}],
  sourceFieldName: [{required: true, message: '请选择出参字段', trigger: 'blur'}],
  targetFieldName: [{required: true, message: '请选择入参字段', trigger: 'blur'}],
});
const batchFormData = ref({
  list: []
});
const sourceNodeList = ref([]);
const targetFieldList = ref([]);

const openFlowParam = async() => {
  batchFormData.value.list = [];
  if (formData.value.subFlowParam) {
    batchFormData.value.list = JSON.parse(formData.value.subFlowParam) || [];
  }

  if (!formData.value.subFlowId) {
    ElMessage.error("请先选择子流程名称！");
    return;
  }

  const nodeListRes = await api.post("/system/flowNode/queryList", {flowId: props.option.id});
  sourceNodeList.value = nodeListRes.data || [];

  const nodeRes = await api.post("/system/flowNode/queryFirst", { flowId: formData.value.subFlowId });
  if (!nodeRes || !nodeRes.data || !nodeRes.data.modelId) {
    ElMessage.error("子流程首节点未配置节点模型！");
    return;
  }

  const fieldListRes = await api.post("/system/dataField/queryList", { modelId: nodeRes.data.modelId });
  targetFieldList.value = fieldListRes.data || [];

  batchDialogVisible.value = true;
};

const changeNode = async(row) => {
  const node = sourceNodeList.value.find(item => item.id === row.nodeId)
  if (!node || !node.modelId) return;

  const res = await api.post("/system/dataField/queryList", { modelId: node.modelId });
  row.sourceFieldList = res.data || [];
};

const addNew = () => {
  for (let i=0;i<newRow.value;i++) {
    batchFormData.value.list.push({newRowFlag: ++newRowFlag.value});
  }
}

const handleDeleteRow = (row) => {
  for (let i=0;i<batchFormData.value.list.length;i++) {
    if (row.newRowFlag !== undefined && row.newRowFlag === batchFormData.value.list[i].newRowFlag) {
      batchFormData.value.list.splice(i, 1);
      return;
    }
  }
}

const submitBatchForm = () => {
  if (batchFormData.value.list && batchFormData.value.list.length > 0) {
    const list = tool.deepClone(batchFormData.value.list);
    list.forEach(item => delete item['sourceFieldList'])
    formData.value.subFlowParam = JSON.stringify(list);
  } else {
    formData.value.subFlowParam = '';
  }

  batchDialogVisible.value = false;
};

const init = () => {
  modeler.value = props.modeler;
  modeler.value.on('selection.changed', e => {
    selectedElements.value = e.newSelection;
    currElement.value = e.newSelection[0];

    const elementRegistry = modeler.value.get('elementRegistry');
    const taskList = elementRegistry.filter((item) => item.type === 'bpmn:Task'
      || item.type === 'bpmn:ScriptTask'
      || item.type === 'bpmn:ExclusiveGateway'
      || item.type === 'bpmn:ParallelGateway'
      || item.type === 'bpmn:ComplexGateway');
    let maxOrderBy = 0;
    taskList.forEach(task => {
      if (maxOrderBy < parseInt(task.businessObject.$attrs.ordinal || 0)) {
        maxOrderBy = parseInt(task.businessObject.$attrs.ordinal || 0);
      }
    });

    setDefaultProperties(currElement.value, parseInt(maxOrderBy) + 1);
  });

  modeler.value.on('element.changed', e => {
    if (!currElement.value) return;
    const { element } = e;
    if (element.id === currElement.value.id) {
      currElement.value = element;
    }
  });
};

const setDefaultProperties = (element, index) => {
  if (element != null) {
    const businessObject = element.businessObject;
    if (businessObject != null) {
      const attrs = businessObject.$attrs;
      const data = {
        code: businessObject.id || '',
        name: businessObject.name,
        color: attrs.color || '',
        canBack: attrs.canBack || '0',
        canBeBack: attrs.canBeBack || '0',
        canStop: attrs.canStop || '0',
        signatureType: attrs.signatureType || '0',
        modelId: attrs.modelId || '',
        titleFieldName: attrs.titleFieldName || '',
        editPageType: attrs.editPageType || '表单',
        editPageId: attrs.editPageId || '',
        editPageDataParamId: attrs.editPageDataParamId || '',
        viewPageType: attrs.viewPageType || '表单',
        viewPageId: attrs.viewPageId || '',
        viewPageDataParamId: attrs.viewPageDataParamId || '',
        messageType: attrs.messageType || '',
        messageTpl: attrs.messageTpl || '',
        canSubFlow: attrs.canSubFlow || '',
        subFlowId: attrs.subFlowId || '',
        subFlowParam: attrs.subFlowParam || '',
        scriptId: attrs.scriptId || '',
        ordinal: parseInt(attrs.ordinal) || index,
        remark: attrs.remark || ''
      };

      formData.value = Object.assign({}, data);
      changeEditPage();
      changeViewPage();
    }
  }
};

const updateName = (name) => {
  modeler.value.get('modeling').updateLabel(toRaw(currElement.value), name)
};

const updateColor = (color) => {
  if (!color) return;
  const data = { stroke: color, fill: getLightColor(color, 9/10) };
  modeler.value.get('modeling').setColor([toRaw(currElement.value)], data);
  updateField("color", color);
};

const updateField = (type, value) => {
  const props = {};
  props[type] = value;
  modeler.value.get('modeling').updateProperties(toRaw(currElement.value), props);
};

const changeEditPage = () => {
  if (!formData.value.editPageId) {
    editPageParamList.value = [];
    return;
  }

  api.post('/system/pageParam/queryList', {pageId: formData.value.editPageId}).then(res => {
    editPageParamList.value = res.data || [];
  });
};

const changeViewPage = () => {
  if (!formData.value.viewPageId) {
    viewPageParamList.value = [];
    return;
  }

  api.post('/system/pageParam/queryList', {pageId: formData.value.viewPageId}).then(res => {
    viewPageParamList.value = res.data || [];
  });
};

const isLine = computed(() => {
  return currElement.value && currElement.value.type.includes('SequenceFlow')
});

const isTask = computed(() => {
  return currElement.value && currElement.value.type === 'bpmn:Task';
});

const isSendTask = computed(() => {
  return currElement.value && currElement.value.type === 'bpmn:SendTask';
});

const isScriptTask = computed(() => {
  return currElement.value && currElement.value.type.includes('ScriptTask')
});

const isNode = computed(() => {
  return currElement.value && (currElement.value.type.includes('Task')
    || currElement.value.type.includes('ExclusiveGateway')
    || currElement.value.type.includes('ParallelGateway')
    || currElement.value.type.includes('ComplexGateway'))
});

watch(() => formData.value, () => {
  updateName(formData.value.name);
  updateColor(formData.value.color);
  updateField('buttonName', formData.value.buttonName);
  updateField('canBack', formData.value.canBack);
  updateField('canBeBack', formData.value.canBeBack);
  updateField('canStop', formData.value.canStop);
  updateField('signatureType', formData.value.signatureType);
  updateField('modelId', formData.value.modelId);
  updateField('titleFieldName', formData.value.titleFieldName);
  updateField('editPageType', formData.value.editPageType);
  updateField('editPageId', formData.value.editPageId);
  updateField('editPageDataParamId', formData.value.editPageDataParamId);
  updateField('viewPageType', formData.value.viewPageType);
  updateField('viewPageId', formData.value.viewPageId);
  updateField('viewPageDataParamId', formData.value.viewPageDataParamId);
  updateField('messageType', formData.value.messageType);
  updateField('messageTpl', formData.value.messageTpl);
  updateField('canSubFlow', formData.value.canSubFlow);
  updateField('subFlowId', formData.value.subFlowId);
  updateField('subFlowParam', formData.value.subFlowParam);
  updateField('scriptId', formData.value.scriptId);
  updateField('ordinal', formData.value.ordinal);
  updateField('remark', formData.value.remark);
}, {deep: 1});

watch(() => props.modeler, () => {
  init();
});

onMounted(() => {
  init()
});
</script>

<style scoped>
:root {
  --node-font-color: '';
}
.custom-properties-panel {
  position: absolute;
  right: 10px;
  top: 65px;
  width: 300px;
  background: #FAFAFA;
  border: solid 1px rgba(0, 0, 0, 0.09);
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
  padding: 20px;
  z-index: 999;
  overflow: auto;
  max-height: calc(100vh - 200px);
  .el-form .el-form-item {
    margin-bottom: 10px!important;
  }
}
.custom-properties-panel input,
.custom-properties-panel textarea {
  padding: 4px 11px;
  color: rgba(0, 0, 0, 0.65);
  font-size: 14px;
  background-color: #fff;
  background-image: none;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  transition: all 0.3s;
  outline: none;
}
.custom-properties-panel label {
  font-weight: bold;
}
.custom-properties-panel button + button {
  margin-left: 10px;
}
.param-item {
  display: flex;
  flex-direction: row;
  width: 100%;
  .param-field {
    width: 70px;
    flex-shrink: 0;
  }
  .param-split {
    width: 44px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
  }
  .param-page {
    flex-grow: 1;
  }
}
.param-item+.param-item {
  margin-top: 5px;
}
.tpl-box div:nth-of-type(n+2){
  padding-left: 20px;
}
</style>